package org.artifact.xlsx;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.json.JSONUtil;
import cn.hutool.poi.excel.ExcelReader;
import cn.hutool.poi.excel.ExcelUtil;
import lombok.SneakyThrows;
import org.yaml.snakeyaml.Yaml;

import java.io.File;
import java.io.FileInputStream;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class ClientConvert extends AbstractConvert {

    public static String LINE_SEPARATOR = java.security.AccessController
            .doPrivileged(new sun.security.action.GetPropertyAction("line.separator"));

    @Override
    void convertXlsx(File file, String outputPath) {
        ExcelReader reader = ExcelUtil.getReader(file);
        reader.setIgnoreEmptyRow(true);


        String fileName = FileUtil.mainName(file);
        File outputFile = FileUtil.newFile(outputPath + File.separator + getDir() + File.separator + fileName + ".lua");
        List<Map<String, Object>> readAll = reader.readAll();
        StringBuffer sb = new StringBuffer();
        sb.append("local " + fileName + " = {" + LINE_SEPARATOR);

        Map<String, Object> types = new HashMap<String, Object>();

        int row = 0;
        for (Map<String, Object> map : readAll) {
            row++;
            switch (row) {
                case 1:
                    types = map;
                    break;
                case 2:
                case 3:
                    break;
                default:
                    int id = MapUtil.getInt(map, "id");
                    sb.append("	[" + id + "] = ");
                    sb.append("{");
                    convertline(sb, types, map);
                    sb.append("}");
                    if (row < readAll.size()) {
                        sb.append(",");
                    }
                    sb.append(LINE_SEPARATOR);
                    break;
            }
        }
        sb.append("}");
        FileUtil.writeUtf8String(sb.toString(), outputFile);
    }


    private static void convertline(StringBuffer sb, Map<String, Object> types, Map<String, Object> map) {
        int i = 0;
        for (Map.Entry<String, Object> e : map.entrySet()) {
            i++;
            sb.append(e.getKey());
            sb.append(" = ");
            convertLuaObject(sb, MapUtil.getStr(types, e.getKey()), e.getValue() == null ? "" : e.getValue());
            if (i < map.size()) {
                sb.append(", ");
            }
        }
    }


    private static void convertLuaObject(StringBuffer sb, String type, Object value) {
        switch (type) {
            case TYPE_INT:
                sb.append(Convert.toNumber(value, 0));
                break;
            case TYPE_INT_ARRAY:
                Number[] numbers = value == null ? new Number[0] : Convert.toNumberArray(value);
                sb.append("{");
                for (Number number : numbers) {
                    sb.append(number.toString());
                    // 不是最后一个才加逗号
                    if (numbers.length - 1 != ArrayUtil.indexOf(numbers, number)) {
                        sb.append(", ");
                    }
                }
                sb.append("}");
                break;
            case TYPE_STRING:
                sb.append(value == null ? "\"\"" : "\"" + value.toString() + "\"");
                break;
            case TYPE_TXT:
                String md5 = SecureUtil.md5(value.toString());
                i18n.put(md5, value.toString());
                sb.append(value == null ? "\"\"" : "\"" + md5 + "\"");
                break;
            case TYPE_STRING_ARRAY:
                String[] strings = value == null ? new String[0] : Convert.toStrArray(value);
                sb.append("{");
                for (String str : strings) {
                    sb.append("\"").append(str).append("\"");
                    // 不是最后一个才加逗号
                    if (strings.length - 1 != ArrayUtil.indexOf(strings, str)) {
                        sb.append(", ");
                    }
                }
                sb.append("}");
                break;
            case TYPE_JSON:
                sb.append(value == null ? "{}" : jsonToTable(JSONUtil.toJsonStr(value)));
                break;
            case TYPE_MAP:
                sb.append("{");
                List<String> strs = StrUtil.splitTrim(value.toString(), "|");
                for (String str : strs) {
                    int[] kv = StrUtil.splitToInt(str, "=");
                    sb.append("[" + kv[0] + "] = " + Convert.toNumber(kv[1], 0));
                    // 不是最后一个才加逗号
                    if (strs.size() - 1 != strs.indexOf(str)) {
                        sb.append(", ");
                    }
                }
                sb.append("}");
                break;
        }
    }

    static String jsonToTable(String json) {
        json = json.replaceAll("\"(\\w+)\"(\\s*:\\s*)", "$1$2");
        json = json.replaceAll(":", "=");
        json = json.replaceAll("\\[", "{");
        json = json.replaceAll("]", "}");
        return json;
    }

    @SneakyThrows
    @Override
    void convertYml(File file, String outputPath) {
        String fileName = FileUtil.mainName(file);
        Yaml yaml = new Yaml();
        Map result = (Map) yaml.load(new FileInputStream(file));
        String json = JSONUtil.toJsonStr(result);
        String formatJson = JSONUtil.formatJsonStr(json);
        String table = jsonToTable(formatJson);
        File outputFile = FileUtil.newFile(outputPath + File.separator + getDir() + File.separator + fileName + ".lua");
        FileUtil.writeUtf8String(table, outputFile);
    }

    @Override
    String getDir() {
        return "client";
    }

    @Override
    void writeI18nFile(String outputPath) {
        File outputFile = FileUtil.newFile(outputPath + File.separator + getDir() + File.separator + "i18n.lua");
        StringBuffer sb = new StringBuffer();
        sb.append("local i18n = {" + LINE_SEPARATOR);
        int row = 0;
        for (Map.Entry<String, String> e : i18n.entrySet()) {
            row++;
            sb.append(" [\"" + e.getKey() + "\"] = ").append("\"").append(e.getValue()).append("\"");
            if (row < i18n.size()) {
                sb.append(",");
            }
            sb.append(LINE_SEPARATOR);
        }
        sb.append("}");
        FileUtil.writeUtf8String(sb.toString(), outputFile);
    }
}
